/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package unb.wikinarua.geopartitura;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Timer;
import java.util.TimerTask;

import org.puredata.android.service.PdService;
import org.puredata.core.PdBase;
import org.puredata.core.utils.IoUtils;

import unb.wikinarua.geopartitura.http.HttpRequest;
import unb.wikinarua.geopartitura.model.Vibration;
import unb.wikinarua.geopartitura.util.Constants;
import unb.wikinarua.geopartitura.util.XMPPConstants;
import unb.wikinarua.geopartitura.view.DrawView;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.res.Resources;
import android.graphics.Color;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.provider.Settings.Secure;
import android.telephony.TelephonyManager;
import android.util.Log;



public class Main extends Activity implements LocationListener {

	// Handler Constants
	public static final int REFRESH_VIEW = 0;
	public static final int VIBRATE_LINE = 1;
	public static final int UPDATE_POI = 2;
	public static final int REQUEST = 3;
	
	// DrawView
	private static long FPS = 125;
	private DrawView drawView;
	private Timer drawTimer;
	private int time = 0;
	
	// Request
	private Timer requestTimer;
	private String[] points;
	
	// Info
	private String imei;
	private Location location;
	
	// Location
	private LocationManager mLocationManager;
	
	// Broadcast Receiver
	private BroadcastReceiver msgReceiver;
	
	// PureData
	private PdService pdService = null;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		// Get IMEI
		imei = ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
		
		// PureData Bind Service
		bindService(new Intent(this, PdService.class), pdConnection, BIND_AUTO_CREATE);
		
		// Start Location Listener
		mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, Constants.MIN_TIME, Constants.MIN_DISTANCE, this);
		
		// Add DrawView
		drawView = new DrawView(this);
		drawView.setBackgroundColor(Color.BLACK);
		setContentView(drawView);
		
		// Start DrawTimerTask
		drawTimer = new Timer();
		drawTimer.schedule(new DrawTimerTask(), 0, FPS);
		
		// Start DrawTimerTask
		requestTimer = new Timer();
		requestTimer.schedule(new RequestTimerTask(), 0, Constants.UPDATE_TIME);
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		
		msgReceiver = new BroadcastReceiver() {
			
			@Override
			public void onReceive(Context context, Intent intent) {
				Log.i(Constants.TAG, "OPA");
				PdBase.sendFloat("String" + 1, .7f);
				PdBase.sendFloat("Amp" + 1, 0.5f);
			}
			
		};
		IntentFilter filter = new IntentFilter();
		filter.addAction(XMPPConstants.XMPP_REC_NEW_MSG);
		registerReceiver(msgReceiver, filter);
	}
	
	@Override
	protected void onPause() {
		super.onPause();
		unregisterReceiver(msgReceiver);
	}
	
	@Override
	public void onBackPressed() {
		overridePendingTransition(R.anim.fade, R.anim.hold);
		super.onBackPressed();
	}
	
    @Override
    public void onDestroy() {
    	super.onDestroy();
    	overridePendingTransition(R.anim.fade, R.anim.hold);
    	PdBase.release();
    	try {
    		unbindService(pdConnection);
    	} catch (IllegalArgumentException e) {
    		pdService = null;
    	}
    	mLocationManager.removeUpdates(this);
    	requestTimer.cancel();
    }
	
    /** Location Listener */
    @Override
	public void onLocationChanged(Location location) {
    	if (Constants.DBG) Log.i(Constants.TAG, "lat:" + location.getLatitude() + " lng:" + location.getLongitude());
    	this.location = location;
	}

	@Override
	public void onProviderDisabled(String provider) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onProviderEnabled(String provider) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onStatusChanged(String provider, int status, Bundle extras) {
		// TODO Auto-generated method stub
		
	}
	
	/** PureData Service */
	private final ServiceConnection pdConnection = new ServiceConnection() {
		
		@Override
		public void onServiceDisconnected(ComponentName name) {
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			pdService = ((PdService.PdBinder)service).getService();
			initPd();
		}
		
	};
	
	/** PureData Methods */
	private void initPd() {
		Resources res = getResources();
		File patchFile = null;
		try {
			PdBase.subscribe("android");
			InputStream in = res.openRawResource(R.raw.geopartitura_actual);
			patchFile = IoUtils.extractResource(in, "geopartitura_actual.pd", getCacheDir());
			PdBase.openPatch(patchFile);
			startAudio();
		} catch (IOException e) {
			Log.e(Constants.TAG, e.getMessage(), e);
		} finally {
			if (patchFile != null) 
				patchFile.delete();
		}
	}
	
	private void startAudio() {
		String name = getResources().getString(R.string.app_name);
		try {
			pdService.initAudio(-1, -1, -1, -1);   // negative values will be replaced with defaults/preferences
			pdService.startAudio(new Intent(this, Main.class), R.drawable.icon, name, "Return to " + name + ".");
		} catch (IOException e) {
			Log.e(Constants.TAG, e.getMessage(), e);
		}
	}
	
	
	/** Handler */
	public Handler handler = new Handler() {
		
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case REFRESH_VIEW:
				drawView.setTime(time++);
				drawView.invalidate();
				break;
			case VIBRATE_LINE:
				if (pdService != null) {
					Vibration v = (Vibration) msg.obj;
					
					if (Constants.DBG) Log.i(Constants.TAG, v.getIndex() + ". Str: " + v.getSize() + " Amp: " + v.getAmplitude());
					PdBase.sendFloat("String" + v.getIndex(), v.getSize());
					PdBase.sendFloat("Amp" + v.getIndex(), v.getAmplitude());
				}
				break;
			case UPDATE_POI:
				drawView.clearLines();
				
				try {
					if (Constants.DBG) Log.i(Constants.TAG, drawView.getWidth() + " --- " + drawView.getHeight());
					
					for (String point : points) {
						drawView.addLine(Float.parseFloat(point.split(",")[1]), 
								Float.parseFloat(point.split(",")[0]), 
								(int) (Math.random() * drawView.getColorLength()));
					}
				} catch (Exception e) {
					drawView.randomizeStrings(10);
				}
				break;
			case REQUEST:
				if (location != null)
					new RequestAsyncTask().execute();
				break;
			}
			super.handleMessage(msg);
		}
		
	};
	
	/** Update view TimerTask */
	private class DrawTimerTask extends TimerTask {

		@Override
		public void run() {
			handler.sendEmptyMessage(REFRESH_VIEW);
		}
		
	}
	
	/** Request TimerTask */
	private class RequestTimerTask extends TimerTask {

		@Override
		public void run() {
			handler.sendEmptyMessage(REQUEST);
		}
		
	}
	
	private class RequestAsyncTask extends AsyncTask<Void, Void, String> {

		@Override
		protected String doInBackground(Void... params) {
			return HttpRequest.getRequest(imei, location.getLatitude(), location.getLongitude());
		}
		
		@Override
		protected void onPostExecute(String reqPoints) {
			if (reqPoints != null) {
				points = reqPoints.split(";");
				handler.sendEmptyMessage(UPDATE_POI);
			}
		}
		
	}
	
}